Title: Unsaved stat boosts fix
Author: Assassin
Version: Version 0.20
Applies to: Secret of Evermore -- US version, Spanish, French, German, and English
            European versions
Tested on: US version, and somewhat on the English European version (the Spanish and
           German European versions are identical to it in the involved chunks) and
           French European version

Contents:

        NOTE: These patches are for HEADERED ROMs only!  That means a filesize of
        3146240 bytes.  Don't let any zealots convince you that headers are dangerous!

        StaSav-U.ips = the SoE (USA) patch
        StaSav-E.ips = the SoE (Europe - English, German, and Spanish) patch
        StaSav-F.ips = the SoE (Europe - French) patch

        NStaSavU.ips = the SoE (USA) anti-patch
        NStaSavE.ips = the SoE (Europe - English, German, and Spanish) anti-patch
        NStaSavF.ips = the SoE (Europe - French) anti-patch

        The "Anti-patches" effectively remove this patch.

        readme.txt = this file

        save-load-game-orig.txt = commented original code, both SRAM saving and loading
                                  (SoE US)
        save-stats-fix.asm = commented fixed code, SRAM saving (SoE US).  Also includes
                             how the SoE European patches' offsets differ from the SoE US
                             version's.
        load-stats-fix.asm = commented fixed code, SRAM loading (SoE US).  Also includes
                             how the SoE European patches' offsets differ from the SoE US
                             version's.

ROM Addresses: SoE US - CD/B241 thru CD/B322, CD/B565 thru CD/B646
               SoE European English, German, and Spanish - CD/AFF8 thru CD/B0D9, CD/B31C
                                                           thru CD/B3FD
               SoE European French - CD/AFB6 thru CD/B097, CD/B2DA thru CD/B3BB
  (NOTE: The game actually runs the Bank Cn code in Bank 8n.)

Functions added (SoE USA and SoE European): None
Additional Square functions used (SoE USA and SoE European): None

Urgency: Medium high.  The bug can have a minor to moderate negative effect on character
         stats.  Or if you unequip after performing it, you could underflow and wind up with
         a game-breakingly high Attack or Defense stat (or a high Hit Rate % or Evade % stat
         with seemingly random results).  Fortunately, it is reversible; see the FAQ
         section.  The bug's effects are accentuated by levelling up Atlas, Defend, or Speed
         alchemy, while they're mitigated by levelling up your characters (which increases
         their base stats).  Generally, players will cast stat-boosting alchemy when heading
         off into dangerous areas, and probably won't have them in effect at (mostly serene)
         save points.  This limits how often the bug will be seen "naturally", but it is
         still ripe for abuse by those who know about it.

============================================================================================

The latest versions of all my patches can be found at either of these sites:

http://www14.brinkster.com/assassin17/
http://home.comcast.net/~assassin17/

============================================================================================

TABLE OF CONTENTS

0. Description
1. Cause
2. What Else this Patch Fixes
3. For Testers
4. FAQ
5. Revision History
6. Credits
Unnumbered: Copyright notice

____________________________________________________________________________________________

0. DESCRIPTION
____________________________________________________________________________________________

When saving and loading, the game transfers characters' information (equipment,
known alchemy, statistics, statuses, etc.) between backup variables and current
variables.  However, the wrong bank (30h instead of 7Eh) is used to address
certain current variables, including the overall modifiers to Attack, Defense,
Evade %, and Hit % from status-granting alchemy or items (namely, Atlas,
Defend, and Speed), and an unused boost for Magic Defense.  So after a reload,
the *real* modifiers just keep the value they were given at reset, apparently
zero.  Thus, the combined stat (a sum of a level-based value, and equipment and
spell boosts) is too low.  Worse yet, when the status expires, the modifier
still drops by what it *should* have been, making the statistic lower than it
was pre-spell.  Taking off equipment can even drive it into negative territory,
causing it to be treated as some giant value like 65,500+.

This patch makes the game use the proper bank on saving and loading, thus
ensuring that alchemy-based stat modifiers are retained through the process.

____________________________________________________________________________________________

1. CAUSE
____________________________________________________________________________________________

It was probably just an oversight by Square.  Some variables in these routines (ones with
offsets <= 1FFFh) don't need the bank override, but the others do.  The weird thing is, they
remembered to use 7Eh bank overrides shortly before and immediately after the faulty
instructions.

____________________________________________________________________________________________

2. WHAT ELSE THIS PATCH FIXES
____________________________________________________________________________________________

As mentioned in Section 0, the boy and dog each have a variable for a boost to Magic
Defense, though no known alchemy or item ever uses it.  Should hackers ever give the ability
to boost Magic Defense to something, this patch would ensure that it's saved and loaded
properly.

Then there are two mystery variables (each two bytes in size) for each character: $4F33 and
$4F35 for the Boy, and $4FE1 and $4FE3 for the Dog.  If they're even used, this bugfix will
make them be retained properly.  Maybe one day, they'll be deciphered.

____________________________________________________________________________________________

3. FOR TESTERS
____________________________________________________________________________________________

The actual fix is simple, but the patch is fairly large, as I converted a lot of code into
block moves for space and/or ego reasons.  Any testing is appreciated.  Particularly on the
European versions, as I've tested only Defend alchemy on those (no Atlas or Speed).  Also,
because the German and Spanish versions are identical to the English European in the areas
altered, I've only tested on the English and French European releases.

Please provide feedback on Slick Productions:
http://slickproductions.org/

or on Mnrogar's Den:
http://mnrogar.slickproductions.org/

or PM assassin17 on the GameFAQs message boards:
http://www.gamefaqs.com/

Thanks!

____________________________________________________________________________________________

4. FAQ
____________________________________________________________________________________________

Q: So what determines whether I get merely a lowered stat, or one that underflows and
   becomes uber huge?

A: Current statistic value = base stat value (determined by level, and level for this
                             purpose is regarded as higher if you possess certain Charms)
                             + equipment stat boosts + alchemy/item stat boosts

   The bug causes the "alchemy/item stat boosts" variable to become, after the status
   expires, a negative version of what it was when first casting the spell.  For Defense, if
   you remove Equipment fully, you're left with:

   Current statistic value = base stat value + negated alchemy/item boosts

   For this to be negative, the boost that the Defend alchemy gave your statistic would need
   to be larger than the base stat.

   Weapons and Atlas are a little different, as you can't fight barehanded; you instead
   need to drop down to a weaker weapon.  The formula here would be:

   Current statistic value = base stat value + weak weapon boost + negated alchemy/item
                             boosts

   To make this negative, the boost that the Atlas alchemy gave your statistic would need
   to be larger than the base Attack stat plus the weapon's.

   For Evade % and Hit %, equipment doesn't boost these, so there are no special steps to
   take.  You'd just want the boost from Speed alchemy to exceed your base stat(s).

   Whatever the stat or alchemy involved, leveling up the spell while minimizing leveling
   up your characters can aid in underflowing.  Avoiding or trading away certain Charms can
   keep your base stats lower, but that's a bit drastic for me to bother recommending it.


Q: So how do I reverse this mess?

A: After you've done the bug, and the status wears off (as indicated by the character(s)
   ceasing to flash), making your statistic(s) too low, go save your game again.  Reload,
   and it should be normal.  Because the bug in saving/loading zeroes out the "alchemy/item
   stat boosts" variable, it can flush a negative value from this variable just as well as
   it does a positive one.


Q: I performed the bug with Speed, and my Evade % and Hit Rate % appear wicked high, yet I'm
   not dominating.  What's up?

A: When calculating your character's total Evade or Hit Rate, the game will cap it at 99 if
   it's 100 to 32866.  If it's 32867 to 65535, the game will leave it as-is, since it never
   anticipated the sum being so high.  As for determining chance to hit, there isn't just a
   simple formula, but data tables that are indexed using target Evade % and attacker
   Hit Rate %, under the assumption that ((Statistic + 1) DIV 4) will range from 0 through
   25.  No real capping of your stats is done in the process, so there's a good likelihood
   the hit chance will be retrieved from gibberish if a statistic is too high, particularly
   Evade.

   Thus, using the bug to game your Evade % or Hit Rate % stat isn't feasible unless you're
   willing to study Function 8F/BA06, do some math to figure out where the pointer winds up,
   and then if the pointer is 8000h to FFFFh, study the relevant ROM addresses in Bank 8F
   (if it's 0 to 7FFFh, don't even bother).  And then be prepared to do it all over again
   whenever your character levels up. :P


Q: From Section 0: "Worse yet, when the status expires, the modifier still
   drops by what it *should* have been, making the statistic lower than it was
   pre-spell."  How does it know what to drop by, if the modifier wasn't
   retained through the save?!  And why?  Why not just zero the damned thing,
   instead of subtracting from it?

A: There are actually two variables involved here.  One can best be called
   "Current boost to relevant statistic(s) due to Status X", and another
   "Overall boost to Statistic Y from alchemy/item statuses".  The former is
   properly retained through a save and reload, while the latter isn't.  They
   work like this:

   - When giving Status X to a target from an alchemy casting:
     - Check if target already has the status.  If so, clean up and remove it:
       - Subtract "Current boost to relevant statistic(s) due to Status X" from
         "Overall boost to Statistic Y from alchemy/item statuses", for any
         pertinent statistics.
       - Clear the status, zero its timer, and zero out "Current boost ... due
         to Status X".
     - Give the status, and set its timer to zero.
     - Set "Current boost to relevant statistic(s) due to Status X" to a value
       based on the current spell level and some randomization.
     - For any relevant statistics, add "Current boost ... due to Status X" to
       "Overall boost to Statistic Y from alchemy/item statuses".
   - When Status X expires:
     - Subtract "Current boost to relevant statistic(s) due to Status X" from
       "Overall boost to Statistic Y ...", for any pertinent statistics.
     - Clear the status, zero its timer, and zero out "Current boost ... due to
       Status X".

   That seems overly complex, but it actually gives the game the ability to
   have multiple separate statuses/sources modifying a statistic at one time.
   Even though I don't think the game makes use of this robustness, it's
   something I want to keep, and simply zeroing "Overall boost to Statistic Y
   from alchemy/item statuses" when a status expires would take away the
   capability.

   Also, while the zeroing idea would remedy the nastier consequence of the bug
   (i.e. a stat dropping to below its pre-alchemy boost level), it still
   wouldn't address the stat boost being lost through a save and reload.

   By the way, the cumulative nature of boosts is relevant in another bug
   (which involves the subtraction of boosts when undoing statuses upon death),
   and in my upcoming fix for it.


Q: I noticed that your prior SoE patches all have version numbering like "Beta 0.nn",
   whereas this one is "Version 0.20".  Does this change mean anything as to the readiness
   of the patches?

A: Nope. :)  My first couple patches (for Final Fantasy VI/IIIus) would start at
   "Version 1.0", like a normal person does.  Then I got more tentative, and started doing
   "Beta 0.20" and such.  In 2012, I stopped using the Beta for that game's patches, because
   the sub-1.0 part ought to be sign enough that these things are not guaranteed, and should
   not be used in a fire truck, panic room, or space mission.  Now I'm finally following
   suit for Secret of Evermore.

____________________________________________________________________________________________

5. REVISION HISTORY
____________________________________________________________________________________________

Version 0.20 : July 4-5, 2013; August 31, 2013; September 1-2, 4, 10-16, 19-21, 2013;
               October 2-3, 6, 9-12, 15, 21, 26, and 30, 2013; November 7 and 12-13, 2013:

  - February 19, 2002: t19wingsd posts about the bug in androl's "Bugs and glitches in the
    game, collect them here" topic on GameFAQs.  He/she doesn't seem to know exactly what
    caused the bug, but his/her post includes the steps needed to achieve it.
  - December 28-29, 2002: Leo0820 and Janitor discuss the bug more in the same thread, again
    involving Defend, and get more specific about the cause (i.e. saving and loading) and
    how to wrap the stat into uber-high values.  Furthermore, Janitor conveyed that Atlas
    and Speed were also susceptible.
  - May 1, 2003: Again in the same topic, SuperVolt posts that one can reverse the bug by
    "reset[ting] the game without Speed/Atlas/Defend active" (presumably saving first).
  - August 21, 2005: Saturn uses the Atlas form of the bug in a TAS (Tool-Assisted
    Speedrun).
  - November 2007 or earlier: Iron Knuckle includes the bug in his FAQ/Walkthrough, with a
    fairly specific description.
  - October 27, 2009: Saturn posts a "Secret of Evermore Trick - Atlas Glitch" video on
    YouTube, which is more specific yet about the workings of the bug.
  - July 4-5, 2013: I decode a few bytes relative to statuses (on Boy).  Found where stats
    are copied to/from SRAM.  Discovered cause of bug, present in both save loading and
    storing.  Wrote fixed code for loading.  Was able to rely on redundancies to make loops
    and actually come out ahead a lot of net bytes.  Wrote bug description, as well as the
    sentence-long patch description.  Wrote FAQ entry about the stat modifier variables that
    are and aren't retained through save and reload.
  - August 31 - September 2, 2013: Commented much of original's and fix's file loading code,
    and much of original file saving code.  Improved (and lengthened) bug description a
    little.
  - September 4, 2013: Commented DMA parts of saving and loading code.  Pretty sparse, as
    there's such a wide range of bytes transferred.
  - September 10-15, 2013: Wrote fixed code for game saving.  Shrunk some of my loading and
    saving code to no longer use bank overrides where unnecessary (I was being overly
    cautious).  Dawned on me that MVN or MVP might be even better than looping "LDA / STA"
    code, mainly for speed and somewhat for size.  Wrote a little of that.  Before going
    further, asked on ROMHacking.net whether having a Block Move done by an interrupt that
    occurs in the middle of an earlier Block Move would uniquely screw up anything (even
    though I really doubted game saving or loading would be done by an interrupt).  Compared
    game save routine from all 5 versions of the game.  Learned that the European ones are
    very similar to the U.S., and mostly identical to each other (save the French).  The
    only difference in my patch will be the starting address of the modifications.  The same
    will be true for the patch of the game load routine, which is what I compared next.
    There are more version differences elsewhere in the function than in the game save
    routine, but I needn't worry about those.  Got answers from STARWIN and Nightcrawler on
    Romhacking.net that one block move interrupting another should be safe, provided A, X,
    and Y are preserved.  Finished converting fix code to use block moves.
  - September 16, 2013: Inspired by a ninakoru post on GameFAQs, added "items" to "alchemy
    and statuses" as a potential source of statistic boosts.  I wanted to be general and
    theoretical in some of my documentation, rather than just listing the 3 alchemy spells
    that do give boosts, so this change made sense.
  - September 19-21: Added very minor European differences to .asm fix files.  Made U.S.
    patch and anti-patch.  Tested Atlas on Boy, and Speed and Defend on both characters.
  - October 2-3, 2013: Made European (English, German, and Spanish) patch and anti-patch.
    Made European French patch and anti-patch.  Tested European English: made sure unboosted
    stats were preserved through just a normal save, and tested Defend on boy and dog
    (hacked in to my first save in Fire Eyes' village at Inn).  Then verified bug was on
    original game.  Too lazy to try Atlas and Speed, but they should work.
  - October 6: Did same tests on European French.
  - October 9-12, 15: Started on this Readme.  Mostly amending aforementioned bug and patch
    description and FAQ entry, but also started on header.  Wrote Urgency section of Readme,
    and three more FAQs.  Wrote "For Testers" section, and did a little more work on header.
  - October 21 and 26: Wrote much of Credits section of Readme.  Realized that instances of
    bug couldn't be strung together to repeatedly lower a stat; corrected a couple parts of
    Readme accordingly.  Not sure why I ever thought this.  Simultaneously realized that the
    bug is reversible; explained how, and amended Urgency field.  Improved FAQ entry on
    Speed some.  Finished off Readme header.
  - October 30; November 7 and 12: Watched SaturnTAS's Atlas Glitch YouTube video, which I'd
    first seen months back.  As a result, corrected my claim that one could just "unequip"
    to lower one's stats; for weapons, you instead need to drop down to a weaker one.  Wrote
    much of this Revision History.  Man, it's big.  Finished off Credits, after finding more
    people in old GameFAQs topic that had further insights on bug.  Finished off Revision
    History.  Copy and pasted original disassembly file from a Bank 8D disassembly.
  - November 13, 2013: Released patch.

____________________________________________________________________________________________

6. CREDITS
____________________________________________________________________________________________

  - t19wingsd for discovering and posting about the bug, as involving the Defend alchemy and
    Defense statistic -- both the stat dropping to small values, then underflowing to a huge
    one.

  - Leo0820 and Janitor for discussing the bug (with Defend) further.  Janitor nailed down
    game saving being the cause, and identified that Atlas and Speed were also susceptible.
    Leo0820 then provided specific steps to trigger the bug, involving both the initial
    reset in the statistic boost, and the stat's wrapping to 65,000+.

  - SuperVolt for posting how to reverse the bug.

  - Iron Knuckle aka Telago for his fine guide, containing a decent explanation of the bug,
    which reminded me of its existence, and informed that unequipping is a good way to get
    stat wrapping.  Check out his guide on GameFAQs, and his website here:
    https://sites.google.com/site/yaworg/

  - Saturn for a tutorial YouTube video on the bug, which advised that you'll want to drop
    to a weaker weapon after Atlas wears off, reminding me that this game makes you keep a
    weapon equipped at all times.  My initial saying to "unequip" was a bit lacking in
    realism. :/  Behold his classic TAS of this game:
    http://tasvideos.org/396M.html
    And give his website a look, too:  http://www.freewebs.com/saturnsmovies/

  - ninakoru, author of the thorough "Secret of Evermore Balance Patch" (and "Hard Mode"
    variant).  Reading a post of his informed me to add "items" to "alchemy statuses" as a
    potential source of statistic boosts in my documentation.  Visit his website at:
    http://www.ninakoru.com/

  - STARWIN and Nightcrawler for convincing me that it would be safe for an interrupt
    routine to use block moves (i.e. MVN or MVP), even if it might interrupt an existing
    block move, provided that the A, X, and Y registers are preserved.  They gave me good
    insight as to how these instructions work.  (It's very unlikely that the game either
    saves or loads using interrupts, but I decided to pose the question on Romhacking.net
    as a hypothetical anyway, given the routines I edited don't originally use block moves.)
    Also, to KingMike for replying in my topic.  As it turns out, Nightcrawler has a
    website:
    http://www.romhacking.net/

  - John David Ratliff for writing the Secret of Evermore SRAM Document, which aided in my
    commenting of the checksum function in the original disassembly.  Get SRAM editors,
    savestates, the newest version of the SRAM document, and more at emuWorks:
    http://games.technoplaza.net/

  - Arnold Neustadter and Hildaur Neilsen for inventing the Rolodex, which I used to keep
    track of everybody in this Credits section.

____________________________________________________________________________________________

Secret of Evermore copyright 1995 Squaresoft.
This readme and all other files in the archive (as listed above)
  copyright 2013 Assassin.
All rights reserved.
